#include <OSAL/OSAL.h>
#include <UTIL/Util.h>

#define _THREAD_RUN_F        (0x1)
#define _THREAD_ASK_EXIT_F   (0x2)

#define SET_RUN()            SET_FLAG(m_Flag, _THREAD_RUN_F)
#define IS_RUN()             (HAS_FLAG(m_Flag, _THREAD_RUN_F)!= 0)
#define RESET_RUN()          RESET_FLAG(m_Flag, _THREAD_RUN_F)

#define SET_ASK_EXIT()       SET_FLAG(m_Flag, _THREAD_ASK_EXIT_F)
#define IS_ASK_EXIT()        (HAS_FLAG(m_Flag, _THREAD_ASK_EXIT_F)!= 0)
#define RESET_ASK_EXIT()     RESET_FLAG(m_Flag, _THREAD_ASK_EXIT_F)
CThread::CThread(
    void (*start_address)(void*),
    void* pThreadData)
{
    m_start_address = start_address;
    m_pThreadData = pThreadData;
    m_Flag = 0;
    memset(&m_thread, 0, sizeof(m_thread));
    RESET_RUN();
}

CThread::~CThread(void)
{
    if(IS_RUN()) {
        printf("CThread::~CThread: (WARNING) thread was not explicitly terminated, destructor will try ...\n");
        Exit(true);
    }
}

bool
CThread::Run(void)
{
    RESET_ASK_EXIT();

    if(IS_RUN()) {
        printf("CThread::Run: Thread has already been running\n");
        return false;
    }

    if(osal_ThreadBegin(m_start_address, m_pThreadData, 0, 0, &m_thread) != S_OK) {
        printf("CThread::Run: osal_ThreadBegin failed\n");
        assert(0);
        return false;
    }

    SET_RUN();
    return true;
}

bool
CThread::IsRun(void)
{
    return IS_RUN();
}

void
CThread::Exit(bool bWaitForExit)
{
    if(!IS_RUN())
        return;

    SET_ASK_EXIT();

    if(bWaitForExit) {
        osal_ThreadEnd(&m_thread, TIME_INFINITY);
        RESET_RUN();
    }
}

bool
CThread::IsAskToExit(void)
{
    return IS_ASK_EXIT();
}
